/*  This file is part of -_-.

    -_- is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    -_- is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with -_-.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2012-2013 Oliver Katz */

#ifndef __VISUAL_H
#define __VISUAL_H

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <sstream>

#include <directfb.h>

using namespace std;

//namespace sleepyface::visual
namespace sleepyface
{
	namespace visual
	{
		//class Region: a region on screen
		class Region
		{
		private:
			int x0, y0, x1, y1;

		public:
			Region(); //methodof Region: initializer
			Region(int x, int y); //methodof Region: initializer with point
			Region(int x0, int y0, int x1, int y1); //methodof Region: initializer with rectangle
			
			int getX0(); //methodof Region: gets the first x coordinate
			int setX0(int x); //methodof Region: sets the first x coordinate
			int getY0(); //methodof Region: gets the first y coordinate
			int setY0(int y); //methodof Region: sets the first y coordinate
			int getX1(); //methodof Region: gets the second x coordinate
			int setX1(int x); //methodof Region: sets the second x coordinate
			int getY1(); //methodof Region: gets the second y coordinate
			int setY1(int y); //methodof Region: sets the second y coordinate
			
			int getWidth(); //methodof Region: gets the width of the region
			int setWidth(int w); //methodof Region: sets the second x coordinate relative to the first
			int getHeight(); //methodof Region: gets the height of the region
			int setHeight(int h); //methodof Region: sets the second y coodinate relative to the first

			bool within(Region coord); //methodof Region: checks to see if coord (a point) is within the region
			bool inside(Region region); //methodof Region: checks to see if region (a rectangle) is fully inside the region
			
			string display(); //methodof Region: displays the region
		};

		Region coordBox(int x0, int y0, int x1, int y1); //method: creates a region from the coordinate box
		Region offsetBox(int x0, int y1); //method: creates a region from two offsets
		Region sizeBox(int w, int h); //method: creates a region at 0x0 from two sizes
		Region coordSizeBox(int x0, int y0, int w, int h); //method: creates a region relative to the first two coordinates with specified size

		//class Color: a hexidecimal color
		class Color
		{
		private:
			unsigned char r, g, b, a;

		public:
			Color(); //methodof Color: initializer
			Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a); //methodof Color: initializer with alpha channel
			Color(unsigned char r, unsigned char g, unsigned char b); //methodof Color: initializer with fully opaque alpha channel
			Color(string s); //methodof Color: initializer from string
			
			int getR(); //methodof Color: gets red
			int getG(); //methodof Color: gets green
			int getB(); //methodof Color: gets blue
			int getA(); //methodof Color: gets alpha

			string display(); //methodof Color: displays the color
		};

		class Renderer;

		//class Surface: a renderable surface on the screen
		class Surface
		{
		private:
			Region region;
			IDirectFBSurface *surf;

		public:
			Surface(); //methodof Surface: initializer
			Surface(Region r, Renderer &renderer); //methodof Surface: initializer with screen region and renderer
			Surface(IDirectFBSurface *s); //methodof Surface: initializer from raw DirectFB surface
			~Surface(); //methodof Surface: uninitializer

			Region &getRegion(); //methodof Surface: gets reference to the screen region of the surface
			
			IDirectFBSurface *getIDirectFBSurface(); //methodof Surface: gets the raw DirectFB surface
			
			int rect(Region reg, Color col); //methodof Surface: renders a rectangle to the surface
			int line(Region reg, Color col); //methodof Surface: renders a line to the surface
			int text(Renderer renderer, Region reg, Color col, string f, string s); //methodof Surface: renders text to the surface (font 'f' must be loaded in the renderer)
			
			int renderTo(Surface s, Region myreg, Region theirreg); //methodof Surface: renders the contents of the surface to another surface
			//argof renderTo: Region myreg: the region of the surface to render from
			//argof renderTo: Region theirreg: the region to render to on the destination surface

			string display(); //methodof Surface: displays the surface
		};

		//class Renderer: a renderer for the framebuffer
		class Renderer
		{
		public:
			typedef int (*renderCallback)(Renderer&); //memberof Renderer: a callback type for updating the screen
			typedef int (*keyPressCallback)(Renderer&, unsigned char); //memberof Renderer: a callback type for handling a key press
			typedef int (*keyReleaseCallback)(Renderer&, unsigned char); //memberof Renderer: a callback type for handling a key release
			typedef int (*motionCallback)(Renderer&, int, int); //memberof Renderer: a callback type for handling mouse motion
			typedef int (*buttonPressCallback)(Renderer&, int); //memberof Renderer: a callback type for handling a mouse button press
			typedef int (*buttonReleaseCallback)(Renderer&, int); //memberof Renderer: a callback type for handling a mouse button release

		private:
			IDirectFB *dfb;
			map<unsigned int, DFBInputDeviceDescription> devs;
			IDirectFBEventBuffer *ebuf;
			map<string, IDirectFBFont *> fonts;
			map<int, Surface> surfaces;
			Surface pri;

			bool keystates[256];
			bool buttonstates[5];
			int xstate, ystate;

			renderCallback renderHandler;
			keyPressCallback keyPressHandler;
			keyReleaseCallback keyReleaseHandler;
			motionCallback motionHandler;
			buttonPressCallback buttonPressHandler;
			buttonReleaseCallback buttonReleaseHandler;

		public:
			Renderer(); //methodof Renderer: initializer

			int init(int *argc, char ***argv); //methodof Renderer: initalizes from command line arguments
			int halt(); //methodof Renderer: halts the renderer
			int run(); //methodof Renderer: runs the rendering main-loop

			int bindRenderHandler(renderCallback c); //methodof Renderer: binds a render callback
			int bindKeyPressHandler(keyPressCallback c); //methodof Renderer: binds a key press callback
			int bindKeyReleaseHandler(keyReleaseCallback c); //methodof Renderer: binds a key release callback
			int bindMotionHandler(motionCallback c); //methodof Renderer: binds a mouse motion callback
			int bindButtonPressHandler(buttonPressCallback c); //methodof Renderer: binds a mouse button press handler
			int bindButtonReleaseHandler(buttonReleaseCallback c); //methodof Renderer: binds a mouse button release handler

			bool getKeyState(unsigned char k); //methodof Renderer: gets the state of key 'k' (true if pressed)
			bool getButtonState(unsigned int b); //methodof Renderer: gets the state of button 'b' (true if clicked)
			int getXState(); //methodof Renderer: gets the current mouse's x coordinate
			int getYState(); //methodof Renderer: gets the current mouse's y coordinate

			int loadFont(string path, int size); //methodof Renderer: loads a new font from 'path' at size 'size'
			IDirectFBFont *getFont(string path); //methodof Renderer: returns the DirectFB font object
			int getTextWidth(string path, string text); //methodof Renderer: gets the width of string 'text' in font loaded as 'path'
			int unloadFont(string path); //methodof Renderer: unloads a font
			int loadImage(string path, Region &r); //methodof Renderer: loads an image to a surface named 'path'
			//argof loadImage: Region &r: pass a blank region and the size of the image will be filled in
			
			Surface &getPrimary(); //methodof Renderer: gets the primary rendering surface
			IDirectFB *getDFB(); //methodof Renderer: gets the main DirectFB object
			
			int loadSurface(Surface s); //methodof Renderer: loads a new surface
			vector<int> listSurfaces(); //methodof Renderer: lists the loaded surfaces
			Surface &getSurface(int s); //methodof Renderer: gets the surface from a name
			int unloadSurface(int s); //methodof Renderer: unloads a surface
		};
	}
}

#endif
